home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Games
/
WarpQuake
/
Src
/
snd_amiga.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-05-22
|
14KB
|
437 lines
/*
Copyright (C) 2000 Peter McGavin.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// snd_amiga.c
#include <exec/exec.h>
#include <dos/dos.h>
#include <graphics/gfxbase.h>
#include <devices/audio.h>
#include <devices/ahi.h>
extern struct GfxBase *GfxBase;
#include <clib/alib_protos.h>
#include <powerup/ppcproto/exec.h>
#include <powerup/ppcproto/dos.h>
#include <powerup/ppcproto/graphics.h>
#include <powerup/ppcproto/ahi.h>
#include "quakedef.h"
/**********************************************************************/
extern int desired_speed;
extern int desired_bits;
int using_ahi = FALSE;
/**********************************************************************/
/* AHI */
#define AHIBUFFERSIZE 262144
struct ahi_channel_info {
struct AHIRequest *AHIio;
double starttime;
BOOL sound_in_progress;
};
struct Library *AHIBase = NULL;
static struct MsgPort *AHImp = NULL;
static struct ahi_channel_info ahi_channel_info[2] = {
{NULL, 0.0, FALSE},
{NULL, 0.0, FALSE}
};
static BYTE AHIDevice = -1;
static BOOL ahidevice_is_open = FALSE;
static double ahi_playtime;
static int which_buffer;
/* audio.device */
/* #define BUFFERSIZE 16384 */
#define BUFFERSIZE 4096
#define MAXNUMCHANNELS 4 /* max number of Amiga sound channels */
struct channel_info {
struct MsgPort *audio_mp;
struct IOAudio *audio_io;
double starttime;
BOOL sound_in_progress;
};
static struct channel_info channel_info[MAXNUMCHANNELS] = {
{NULL, NULL, 0.0, FALSE},
{NULL, NULL, 0.0, FALSE},
{NULL, NULL, 0.0, FALSE},
{NULL, NULL, 0.0, FALSE},
};
static int size;
static struct MsgPort *audio_mp = NULL;
static struct IOAudio *audio_io = NULL;
static BOOL audio_is_open = FALSE;
static ULONG clock_constant; /* see Amiga Hardware Manual page 141 */
static UWORD period;
static double twice_real_speed;
/**********************************************************************/
static void stop_ahi_sound (struct ahi_channel_info *c)
{
if (!ahidevice_is_open)
return;
if (c->sound_in_progress) {
AbortIO ((struct IORequest *)c->AHIio);
WaitPort (AHImp);
GetMsg (AHImp);
c->sound_in_progress = FALSE;
}
}
/**********************************************************************/
// Starts an AHI sound in a particular sound channel.
// Use link for double-buffering.
static void start_ahi_sound (struct ahi_channel_info *c,
char *buffer, int length,
struct AHIRequest *link)
{
if (!ahidevice_is_open)
return;
stop_ahi_sound (c);
c->AHIio->ahir_Std.io_Command = CMD_WRITE;
c->AHIio->ahir_Std.io_Flags = 0;
c->AHIio->ahir_Std.io_Message.mn_Node.ln_Pri = -50; /* sound effects */
c->AHIio->ahir_Std.io_Data = buffer;
c->AHIio->ahir_Std.io_Length = length;
c->AHIio->ahir_Type = AHIST_S16S;
c->AHIio->ahir_Frequency = shm->speed;
c->AHIio->ahir_Volume = 0x10000;
c->AHIio->ahir_Position = 0x8000;
c->AHIio->ahir_Link = link;
SendIO ((struct IORequest *)c->AHIio);
c->sound_in_progress = TRUE;
}
/**********************************************************************/
// Stops an audio.device sound channel.
static void stopsound (int cnum)
{
if (!audio_is_open)
return;
if (channel_info[cnum].sound_in_progress) {
AbortIO ((struct IORequest *)channel_info[cnum].audio_io);
WaitPort (channel_info[cnum].audio_mp);
GetMsg (channel_info[cnum].audio_mp);
channel_info[cnum].sound_in_progress = FALSE;
}
}
/**********************************************************************/
// Starts an audio.device sound in a particular sound channel.
static int startsound (int cnum, char *buffer, int length)
{
struct channel_info *c;
if (!audio_is_open)
return 1;
stopsound (cnum);
c = &channel_info[cnum];
c->audio_io->ioa_Request.io_Command = CMD_WRITE;
c->audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
c->audio_io->ioa_Data = buffer;
c->audio_io->ioa_Length = length;
c->audio_io->ioa_Period = period;
c->audio_io->ioa_Volume = 64;
c->audio_io->ioa_Cycles = 0;
BeginIO ((struct IORequest *)c->audio_io);
c->starttime = Sys_FloatTime ();
c->sound_in_progress = TRUE;
return cnum;
}
/**********************************************************************/
qboolean SNDDMA_Init (void)
{
int i, unit = 0;
struct channel_info *c;
UBYTE chans[1];
// printf ("SNDDMA_Init()\n");
if ((shm = (dma_t *)malloc (sizeof(dma_t))) == NULL)
Sys_Error ("malloc() failed");
memset((void*)shm, 0, sizeof(dma_t));
if (COM_CheckParm ("-ahi")) {
if ((unit = COM_CheckParm ("-ahiunit"))) {
if (unit < com_argc-1)
unit = Q_atoi (com_argv[unit+1]);
else
Sys_Error ("You must specify a number after -unit");
}
Con_Printf("Using AHI unit %d.\n", unit);
using_ahi = TRUE;
//#if defined(__SASC) && defined(__PPC__)
// if ((shm->buffer = PPCAllocMem (AHIBUFFERSIZE, MEMF_NOCACHESYNCPPC |
// MEMF_NOCACHESYNCM68K | MEMF_PUBLIC)) == NULL)
//#else
if ((shm->buffer = malloc (AHIBUFFERSIZE)) == NULL)
//#endif
Sys_Error ("malloc() failed");
memset (shm->buffer, 0, AHIBUFFERSIZE);
shm->channels = 2;
shm->speed = desired_speed;
shm->samplebits = 16;
shm->samples = AHIBUFFERSIZE / (shm->samplebits / 8);
shm->submission_chunk = 1;
if ((AHImp = CreateMsgPort ()) == NULL)
Sys_Error ("CreateMsgPort() failed");
for (i = 0; i < 2; i++)
if ((ahi_channel_info[i].AHIio = (struct AHIRequest *)CreateIORequest
(AHImp, sizeof(struct AHIRequest))) == NULL)
Sys_Error ("CreateIORequest() failed");
ahi_channel_info[0].AHIio->ahir_Version = 4;
if ((AHIDevice = OpenDevice (AHINAME, unit,
(struct IORequest *)ahi_channel_info[0].AHIio,
0)) != 0)
Sys_Error ("OpenDevice() failed");
ahidevice_is_open = TRUE;
AHIBase = (struct Library *)ahi_channel_info[0].AHIio->ahir_Std.io_Device;
*ahi_channel_info[1].AHIio = *ahi_channel_info[0].AHIio;
twice_real_speed = 2.0 * (double)shm->speed;
ahi_playtime = ((double)(AHIBUFFERSIZE >> 2)) / (double)shm->speed;
//printf ("ahi_playtime = %f\n", ahi_playtime);
ahi_channel_info[0].starttime = Sys_FloatTime ();
start_ahi_sound (&ahi_channel_info[0], shm->buffer, AHIBUFFERSIZE, NULL);
//printf ("start[0] = %f %f\n", ahi_channel_info[0].starttime,
// ahi_channel_info[0].starttime + ahi_playtime);
ahi_channel_info[1].starttime = ahi_channel_info[0].starttime + ahi_playtime;
start_ahi_sound (&ahi_channel_info[1], shm->buffer, AHIBUFFERSIZE,
ahi_channel_info[0].AHIio);
//printf ("start[1] = %f %f\n", ahi_channel_info[1].starttime,
// ahi_channel_info[1].starttime + ahi_playtime);
which_buffer = 0;
} else { /* audio.device */
Con_Printf("Using audio.device.\n");
using_ahi = FALSE;
if ((shm->buffer = AllocMem (BUFFERSIZE, MEMF_CHIP | MEMF_CLEAR)) == NULL)
Sys_Error ("Out of CHIP memory for sound");
// memset(shm->buffer, 0x80, BUFFERSIZE);
// printf ("Sound buffer at 0x%08x\n", shm->buffer);
shm->channels = 2;
shm->speed = desired_speed;
shm->samplebits = 8;
shm->samples = BUFFERSIZE / (shm->samplebits / 8);
shm->submission_chunk = 1;
if ((audio_mp = CreateMsgPort ()) == NULL ||
(audio_io = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),
MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
Sys_Error ("CreateMsgPort() or AllocMem() failed");
chans[0] = (1 << shm->channels) - 1; /* shm->channels Amiga audio channels */
audio_io->ioa_Request.io_Message.mn_ReplyPort = audio_mp;
audio_io->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
audio_io->ioa_AllocKey = 0;
audio_io->ioa_Data = chans;
audio_io->ioa_Length = sizeof(chans);
if (OpenDevice (AUDIONAME, 0, (struct IORequest *)audio_io, 0) != 0)
Sys_Error ("OpenDevice(\"audio.device\") failed");
audio_is_open = TRUE;
for (i = 0; i < shm->channels; i++) {
c = &channel_info[i];
if ((c->audio_mp = CreateMsgPort ()) == NULL ||
(c->audio_io = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),
MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
Sys_Error ("CreateMsgPort() or AllocMem() failed");
*c->audio_io = *audio_io;
c->audio_io->ioa_Request.io_Message.mn_ReplyPort = c->audio_mp;
c->audio_io->ioa_Request.io_Unit = (struct Unit *)(1 << i);
}
if ((GfxBase->DisplayFlags & REALLY_PAL) == 0)
clock_constant = 3579545; /* NTSC */
else
clock_constant = 3546895; /* PAL */
period = ((clock_constant << 1) + shm->speed) / ((shm->speed) << 1);
twice_real_speed = 2.0 * ((double)clock_constant) / (double)period;
startsound (0, shm->buffer, BUFFERSIZE >> 1);
startsound (1, shm->buffer + (BUFFERSIZE >> 1), BUFFERSIZE >> 1);
}
return 1;
}
/**********************************************************************/
int SNDDMA_GetDMAPos (void)
{
if (shm == NULL || shm->buffer == NULL)
return 0;
if (using_ahi) {
if (!ahi_channel_info[0].sound_in_progress)
shm->samplepos = 0;
else {
struct ahi_channel_info *c, *c2;
double now;
now = Sys_FloatTime ();
c = &ahi_channel_info[which_buffer];
if (now >= c->starttime + ahi_playtime - 0.1 &&
CheckIO ((struct IORequest *)c->AHIio)) {
//printf ("finished[%d] = %f %f\n", which_buffer, now,
// now - (c->starttime + ahi_playtime));
c2 = &ahi_channel_info[1 - which_buffer];
if (c2->starttime > now) {
c2->starttime = now;
//printf ("changed[%d] = %f %f\n", 1 - which_buffer, c2->starttime,
// c2->starttime + ahi_playtime);
}
WaitPort (AHImp);
GetMsg (AHImp);
c->sound_in_progress = FALSE;
if ((now = Sys_FloatTime ()) > (c->starttime =
c2->starttime + ahi_playtime))
c->starttime = now;
start_ahi_sound (c, shm->buffer, AHIBUFFERSIZE,
ahi_channel_info[1 - which_buffer].AHIio);
//printf ("start[%d] = %f %f\n", which_buffer, c->starttime,
// c->starttime + ahi_playtime);
which_buffer = 1 - which_buffer;
c = &ahi_channel_info[which_buffer];
}
shm->samplepos = ((int)((now + ahi_playtime - c->starttime) *
twice_real_speed + 0.5)) & (AHIBUFFERSIZE - 1);
}
} else { /* audio.device */
if (!channel_info[0].sound_in_progress)
shm->samplepos = 0;
else
shm->samplepos = ((int)((Sys_FloatTime() - channel_info[0].starttime)
* twice_real_speed + 0.5))
& (BUFFERSIZE - 1);
}
return shm->samplepos;
}
/**********************************************************************/
void SNDDMA_Shutdown (void)
{
int i;
// printf ("SNDDMA_Shutdown()\n");
for (i = 0; i < 2; i++)
stop_ahi_sound (&ahi_channel_info[i]);
if (ahidevice_is_open) {
CloseDevice ((struct IORequest *)ahi_channel_info[0].AHIio);
ahidevice_is_open = FALSE;
}
for (i = 0; i < 2; i++) {
if (ahi_channel_info[i].AHIio != NULL) {
DeleteIORequest ((struct IORequest *)ahi_channel_info[i].AHIio);
ahi_channel_info[i].AHIio = NULL;
}
}
if (AHImp != NULL) {
DeleteMsgPort (AHImp);
AHImp = NULL;
}
if (audio_is_open) {
if (shm != NULL) {
for (i = 0; i < shm->channels; i++)
stopsound (i);
audio_io->ioa_Request.io_Unit = (struct Unit *)
((1 << shm->channels) - 1); /* free shm->channels channels */
}
CloseDevice ((struct IORequest *)audio_io);
audio_is_open = FALSE;
}
for (i = 0; i < MAXNUMCHANNELS; i++) {
if (channel_info[i].audio_io != NULL) {
FreeMem (channel_info[i].audio_io, sizeof(struct IOAudio));
channel_info[i].audio_io = NULL;
}
if (channel_info[i].audio_mp != NULL) {
DeleteMsgPort (channel_info[i].audio_mp);
channel_info[i].audio_mp = NULL;
}
}
if (audio_io != NULL) {
FreeMem (audio_io, sizeof(struct IOAudio));
audio_io = NULL;
}
if (audio_mp != NULL) {
DeleteMsgPort (audio_mp);
audio_mp = NULL;
}
if (shm != NULL) {
if (shm->buffer != NULL) {
if (using_ahi)
//#if defined(__SASC) && defined(__PPC__)
// PPCFreeMem (shm->buffer, AHIBUFFERSIZE);
//#else
free (shm->buffer);
//#endif
else
FreeMem (shm->buffer, BUFFERSIZE);
shm->buffer = NULL;
}
free ((char *)shm);
shm = NULL;
}
}
/**********************************************************************/
void SNDDMA_Submit (void)
{
// printf ("SNDDMA_Submit()\n");
}
/**********************************************************************/